package com.macvon.ble;

import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.macvon.utils.ToastUtils;

import java.util.List;
import java.util.UUID;

import static android.content.Context.BLUETOOTH_SERVICE;
import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;

public class BleModule extends ReactContextBaseJavaModule {
    public final static UUID CLIENT_CHARACTERISTIC_CONFIG = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb");
    public final static UUID UUID_LOST_SERVICE = UUID.fromString("0000fff0-0000-1000-8000-00805f9b34fb");
    public final static UUID UUID_LOST_WRITE = UUID.fromString("0000fff1-0000-1000-8000-00805f9b34fb");
    public final static UUID UUID_LOST_ENABLE = UUID.fromString("0000fff2-0000-1000-8000-00805f9b34fb");

    private final static String BLE_RECEIVE_DATA = "BLE_RECEIVE_DATA";
    private final static String BLE_CONNECTED = "BLE_CONNECTED";

    private static final int REQUEST_ENABLE_BT = 1;

    private static final String TAG = "BleModule";


    private BluetoothManager mBluetoothManager;
    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
    private BluetoothAdapter mBluetoothAdapter;

    private BluetoothGattServer gattServer;
    private BluetoothGattCharacteristic characterNotify;
    private BluetoothDevice bluetoothDevice;
    private static final int LOCATION_CODE = 1;
    private Callback scanResultCallback;
    ReactApplicationContext reactContext;
    private Callback receivedDataCallback;
    private Handler handler;


    public BleModule(@NonNull ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        this.handler =  new Handler(reactContext.getMainLooper());
        this.initBle();
    }

    @NonNull
    @Override
    public String getName() {
        return "BleMgr";
    }


    private IntentFilter bleFilter() {
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
        return filter;
    }

    private BroadcastReceiver bleReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            switch (intent.getAction()) {
                case BluetoothAdapter.ACTION_STATE_CHANGED:
                    int blueState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, 0);
                    switch (blueState) {
                        case BluetoothAdapter.STATE_CONNECTED:
                            Log.d(TAG,"onReceive---------STATE_CONNECTED");
                            sendEventToJs(BLE_CONNECTED,null);
                            break;
                        case BluetoothAdapter.STATE_TURNING_ON:
                            Log.d(TAG,"onReceive---------STATE_TURNING_ON");
                            break;
                        case BluetoothAdapter.STATE_ON:
                            Log.e(TAG,"onReceive---------STATE_ON");
                            initServer();
                            break;
                        case BluetoothAdapter.STATE_TURNING_OFF:
                            Log.d(TAG,"onReceive---------STATE_TURNING_OFF");
                            break;
                        case BluetoothAdapter.STATE_OFF:
                            Log.d(TAG,"onReceive---------STATE_OFF");
                            break;
                    }
                    break;
            }
        }
    };

    /**
     * 初始化 蓝牙
     */
    @ReactMethod
    private void initBle(){
        reactContext.registerReceiver(bleReceiver,bleFilter());
        if (!reactContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(reactContext, "不支持BLE", Toast.LENGTH_LONG).show();
            return;
        }
        mBluetoothManager = (BluetoothManager) reactContext.getSystemService(BLUETOOTH_SERVICE);
        mBluetoothAdapter = mBluetoothManager.getAdapter();

        if (mBluetoothAdapter == null) {
            Toast.makeText(reactContext, "蓝牙不支持", Toast.LENGTH_LONG).show();
            return;
        }
        if(!mBluetoothAdapter.isEnabled()){
            mBluetoothAdapter.enable();
        }
        else {
//            初始化广播信息
            initServer();
        }
        Log.d(TAG, "BleMgr initialized");
    }

    /**
     * 开始广播
     * @param
     */
    @ReactMethod
    public void startAdvertising(@Nullable Callback receivedDataCallback){
        this.receivedDataCallback = receivedDataCallback;
        if(mBluetoothLeAdvertiser!= null){
            mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mBluetoothLeAdvertiser.startAdvertising(createAdvSettings(true, 0), createAdvertiseData(), mAdvertiseCallback);
                }
            }, 1000);
        }
    }


    /**
     * 关闭广播
     */
    @ReactMethod
    public void stopAdvertising(){
        mBluetoothLeAdvertiser.stopAdvertising(mAdvertiseCallback);
    }

    /**
     * 开启扫描
     */
    @ReactMethod
    public void startScan(Callback scanResultCallback){
        this.scanResultCallback = scanResultCallback;
        BluetoothLeScanner scanner = mBluetoothManager.getAdapter().getBluetoothLeScanner();
        if(scanner != null){
            scanner.startScan(scanCallback);
        }
    }

    /**
     * 停止扫描
     */
    @ReactMethod
    public void stopScan(){
        BluetoothLeScanner scanner = mBluetoothManager.getAdapter().getBluetoothLeScanner();
        if(scanner != null){
            scanner.stopScan(scanCallback);
        }
    }

     /**
     *广播的一些基本设置
     **/
     private AdvertiseSettings createAdvSettings(boolean connectAble, int timeoutMillis) {
        AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder();
        builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED);
        builder.setConnectable(connectAble);
        builder.setTimeout(timeoutMillis);
        builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH);
        AdvertiseSettings mAdvertiseSettings = builder.build();
        if (mAdvertiseSettings == null) {
            Log.e(TAG, "mAdvertiseSettings == null");
        }
        return mAdvertiseSettings;
    }

    public AdvertiseData createAdvertiseData() {
        AdvertiseData.Builder mDataBuilder = new AdvertiseData.Builder();
        mDataBuilder.setIncludeDeviceName(true); //广播名称也需要字节长度
        mDataBuilder.setIncludeTxPowerLevel(true);
        mDataBuilder.addServiceData(ParcelUuid.fromString("0000fff0-0000-1000-8000-00805f9b34fb"),new byte[]{1,2});
        AdvertiseData mAdvertiseData = mDataBuilder.build();
        if (mAdvertiseData == null) {
//            Toast.makeText(MainActivity.this, "mAdvertiseSettings == null", Toast.LENGTH_LONG).show();
            Log.e(TAG, "mAdvertiseSettings == null");
        }
        return mAdvertiseData;
    }

    private ScanCallback scanCallback = new ScanCallback() {

        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            super.onBatchScanResults(results);
            if(scanResultCallback != null){
                scanResultCallback.invoke(results);
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);
        }
    };

    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
        @Override
        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
            super.onStartSuccess(settingsInEffect);
            ToastUtils.showToast(reactContext, "broadcasting", 2000);
        }

        @Override
        public void onStartFailure(int errorCode) {
            super.onStartFailure(errorCode);
            ToastUtils.showToast(reactContext, "开启广播失败 errorCode：" + errorCode, 2000);
        }
    };


    /**
     * 添加服务，特征
     */
    @ReactMethod
    private void initServer() {
        assert mBluetoothAdapter != null;
        mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
        if (mBluetoothLeAdvertiser == null) {
            Toast.makeText(reactContext, "the device not support peripheral", Toast.LENGTH_SHORT).show();
            return;
        }
        //读写特征
        BluetoothGattCharacteristic characterWrite = new BluetoothGattCharacteristic(
                UUID_LOST_WRITE, BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
                BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
        //使能特征
        characterNotify = new BluetoothGattCharacteristic(UUID_LOST_ENABLE,
                BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE , BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);

        characterNotify.addDescriptor(new BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG, BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE));
        //服务
        BluetoothGattService gattService = new BluetoothGattService(UUID_LOST_SERVICE,
                BluetoothGattService.SERVICE_TYPE_PRIMARY);
        //为服务添加特征
        gattService.addCharacteristic(characterWrite);
        gattService.addCharacteristic(characterNotify);

        //管理服务，连接和数据交互回调
        gattServer = mBluetoothManager.openGattServer(this.reactContext,
                new BluetoothGattServerCallback() {

                    @Override
                    public void onConnectionStateChange(final BluetoothDevice device,
                                                        final int status, final int newState) {
                        super.onConnectionStateChange(device, status, newState);
                        bluetoothDevice = device;
                        Log.d(TAG, "onConnectionStateChange:" + device + "    " + status + "   " + newState);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                ToastUtils.showToast(reactContext, "onConnectionStateChange", 2000);
                            }
                        });
                    }

                    @Override
                    public void onServiceAdded(int status,
                                               BluetoothGattService service) {
                        super.onServiceAdded(status, service);
                        Log.d(TAG, "service added");
                    }

//                    外围设备接收到中央设备的读特征值请求
                    @Override
                    public void onCharacteristicReadRequest(
                            BluetoothDevice device, int requestId, int offset,
                            BluetoothGattCharacteristic characteristic) {
                        super.onCharacteristicReadRequest(device, requestId,
                                offset, characteristic);
                        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, null );
                        ToastUtils.showToast(reactContext, "准备开启Wi-Fi扫描", 2000);
//                        开启 Wi-Fi 扫描
//                        wifiManagent.scanWiFi();
//                        successCallback.invoke();
                        Log.d(TAG, "onCharacteristicReadRequest");
                    }

                    @Override
                    public void onCharacteristicWriteRequest(
                            BluetoothDevice device, int requestId,
                            BluetoothGattCharacteristic characteristic,
                            boolean preparedWrite, boolean responseNeeded,
                            int offset, final byte[] value) {
                        super.onCharacteristicWriteRequest(device, requestId,
                                characteristic, preparedWrite, responseNeeded,
                                offset, value);
                        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
                        Log.d(TAG, "onCharacteristicWriteRequest" + value[0]);
                        runOnUiThread(new Runnable() {
                            @SuppressLint("SetTextI18n")
                            @Override
                            public void run() {
                                String msg = new String(value);
//                                if(receivedDataCallback != null){
//                                    receivedDataCallback.invoke(msg);
//                                }
//                                 发送蓝牙消息事件
                                sendEventToJs(BLE_RECEIVE_DATA,msg);
                                Log.i(TAG, "msg#####: " + msg);
                            }
                        });
                    }

                    @Override
                    public void onNotificationSent(BluetoothDevice device, int status) {
                        super.onNotificationSent(device, status);
                        Log.i(TAG, "onNotificationSent: ");
                    }

                    @Override
                    public void onMtuChanged(BluetoothDevice device, int mtu) {
                        super.onMtuChanged(device, mtu);
                    }

                    @Override
                    public void onDescriptorReadRequest(BluetoothDevice device,
                                                        int requestId, int offset,
                                                        BluetoothGattDescriptor descriptor) {
                        super.onDescriptorReadRequest(device, requestId,
                                offset, descriptor);
                        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characterNotify.getValue());
                        Log.d(TAG, "onDescriptorReadRequest");
                    }

                    @Override
                    public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                                                         BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded,
                                                         int offset, byte[] value) {
                        super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded,
                                offset, value);
                        gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value);
//                        characterNotify.setValue("HIHHHHH");
//                        gattServer.notifyCharacteristicChanged(bluetoothDevice, characterNotify, false);
                        Log.d(TAG, "onDescriptorWriteRequest");

                    }

                    @Override
                    public void onExecuteWrite(BluetoothDevice device,
                                               int requestId, boolean execute) {
                        super.onExecuteWrite(device, requestId, execute);
                        Log.d(TAG, "onExecuteWrite");
                    }
                });
        gattServer.addService(gattService);
    }

    /**
     *
     * @param eventName 事件的名称
     * @param obj 对应的Value
     */
    private void sendEventToJs(String eventName,Object obj){
        getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,obj);
    }
}

